// import和require的区别在导出一个对象的时候import导出的可以直接使用而require导出的es6模块会把结果放到default上使用（obj.default.方法）
//  let str=require('./a.js')
// document.querySelector('#app').innerHTML=str
// import './index.css' //在webpack中所有文件都可以看成是模块都可以使用import '路径'来引入但是只支持引入js模块css这种需要配置
// import './index.less' 
// import 'bootstrap'//路径上没加./表示这是一个安装好的模块会去node_modules下查找是es6语法
// // require('@babel/polyfill')
// @log // 装饰器
// class A{
//     a=1
// }
// function log(target){ // 装饰器是一个函数
//     console.log(target)
//     // console.lo(1)
// }
// 'aaa'.includes('a') // includes是es7提供的属于实例上的方法，需要使用包@babel/polyfill来进行重写到Array.prototype上（放入生产环境中）,优化js高级语法的转换
// 本来webpack支持页面改动就跟新但是是浏览器的整体刷新，如果vue项目中使用了vuex这种状态管理
//那么一刷状态数据就初始化了，所以需要在入口文件中做一以下配置来监听热跟新只是跟新改动的地方
//打包过程中图片的使用
// let img=new Image()
// img.src='./xxx.png'// 这样的话打包的时候是不行的默认是字符串必须是img.src=require('./xxx.png') 或者import png from './xxx.png'(返回的图片是一个新的图片地址此时需要file-loader来解析)
// img.src=png
// css 中background:url('./xxx.png') 是支持的因为css-loader会把路径加上require
// <img src='./xxx.png'/> 如果是在html中通过标签的形式引入的话需要一个插件html-withimg-loader
// var url = ''
// if(DEV==='production'){ //DEV是webpack中配置的项目全局变量
//     // 上线的生成环境
//     url='xxxx'
// }else{
//     // 开发环境    
//     url='ooo'
// }
// let xhr=new XMLHttpRequest()
// xhr.open('GET','/api/user',true)
// xhr.onload=function(){
//     console.log(xhr.response)
// }
// // xhr.send()
// import moment from 'moment'
// import 'moment/locale/zh-cn' // 使用了IgnorePlugin排除了locale所以这里要引入需要是简体中文包
// console.log(moment().format('YYYY-MM-DD'))
// console.log(moment().format('h:mm:ss'))
// console.log(moment().format('lll'))
//  import React from 'react'
//  import {render} from 'react-dom'
//  render(<h1>jsx</h1>,window.app)
//  let button=document.createElement('button')
//  button.innerHTML='点击'
//  button.addEventListener('click',function(){
//      // 懒加载，还是草案中的语法 通过jsonp来实现的
//      import('./a.js').then((data)=>{ // 通过import导出的是一个promise对象
//          console.log(data.default)
//      })
//  })
//  document.body.appendChild(button)

//热跟新
// import str from './a'
// console.log(str)
// if(module.hot){
// // module.hot.accept('./a',()=>{
// //     require('./a') // 这里不用import来引入是因为import只能放在文件的顶端
// //     console.log(str) 
// // })
// module.hot.accept()
// }
// tapable的方法实现 使用的都是发布订阅模式
// 同步方法
//1SyncHook 
// class SyncHook{
//     constructor(task){
//         this.tasks=[]
//     }
//     tap(name,fun){
//         this.tasks.push(fun)
//     }
//     call(...args){
//         this.tasks.some((task)=>task(...args))
//     }
// }
// let h=new SyncHook(['name'])
// h.tap('node',(name)=>{
//     console.log('node',name)
// })
// h.tap('js',(name)=>{
//     console.log('js',name)
// })
// h.call('wjy')

// class SyncBailHook{ 一旦发生错误可以阻止接下来的函数的触发
//     constructor(task){
//         this.tasks=[]
//     }
//     tap(name,fun){
//         this.tasks.push(fun)
//     }
//     call(...args){
//         let result
//         let index=0
//         do {
//          result=this.tasks[index++](...args)
//         } while (result===undefined&&index<this.tasks.length)
//     }
// }
// let h=new SyncBailHook(['name'])
// h.tap('node',(name)=>{
//     console.log('node',name)
//     return 'l'
// })
// h.tap('js',(name)=>{
//     console.log('js',name)
// })
// h.call('wjy')
// class SyncLoopHook{//提前绑定的任务数组中的函数执行返回的结果只要不是undefined的就会一直执行
//     constructor(task){
//         this.tasks=[]
//     }
//     tap(name,fun){
//         this.tasks.push(fun)
//     }
//     call(...args){
//       this.tasks.some((task)=>{
//           let result
//           do { // 只要满足条件就一循环
//               result=task(...args)
//           } while (result!=undefined);
//       })
//     }
// }
// let h=new SyncLoopHook(['name'])
// let total=0
// h.tap('node',(name)=>{
//     console.log('node',name)
//     return ++total===3?undefined:'继续执行'
// })
// h.tap('js',(name)=>{ // 函数中不写return就是默认返回undefined
//     console.log('js',name)
// })
// h.tap('react',(name)=>{
//     console.log('react',name)
// })
// h.call('wjy')
// 异步方法 并发
// class AsyncParralleHook{
//         constructor(task){
//             this.tasks=[]
//         }
//         tapAsync(name,fun){
//             this.tasks.push(fun)
//         }
//         callAsync(...args){
//             let finallCallback=args.pop()//把形参列表数组的最后一项从数组中删掉返回值是删除的哪一项，之后的args在使用的时候就不包含最后一项
//             // 传进来的回调函数了
//             let index=0
//             let done=()=>{
//                 index++
//                 if (index == this.tasks.length){ // 在class中必须使用箭头函数不然this指向不对
//                     finallCallback(...args)
//                 }
//             }
//            this.tasks.some((task)=>task(...args,done))
//         }
//     }
//     let h=new AsyncParralleHook(['name'])
//     h.tapAsync('node',(name,cb)=>{
//         setTimeout(function() {
//         console.log('node',name)
//         cb()
//         }, 1000);
//     })
//     h.tapAsync('js',(name,cb)=>{
//         setTimeout(function() {
//             console.log('js',name)
//             cb()
//             }, 1000);
//     })
//     h.callAsync('wjy',function(name){
//         // 这个函数在所有通过tapAsync绑定的异步函数执行完后才会执行
//         console.log(name)
//     })

// class AsyncParralleHook{
//             constructor(task){
//                 this.tasks=[]
//             }
//             tappromise(name,fun){
//                 this.tasks.push(fun)
//             }
//             promise(...args){
//                return Promise.all(this.tasks.map(task=>task(...args)))
//             }
//         }
//         let h=new AsyncParralleHook(['name'])
//         h.tappromise('node',(name)=>{
//             return new Promise((resolve,reject)=>{
//             setTimeout(function() {
//             console.log('node',name)
//             resolve()
//             }, 1000);
//             })
//         })
//         h.tappromise('js',(name)=>{
//             return new Promise((resolve,reject)=>{
//                 setTimeout(function() {
//                     console.log('js',name)
//                     resolve()
//                     }, 1000);
//                 })
//         })
//         h.promise('wjy').then(()=>{
//             console.log('end')
//         })
    
// 异步方法 串行 

//  class AsyncSeriesHook{
//             constructor(task){
//                 this.tasks=[]
//             }
//             tapAsync(name,fun){
//                 this.tasks.push(fun)
//             }
//             callAsync(...args){
//                let finallCallback=args.pop()
//                let index=0
//                let next=()=>{
//                 if(index===this.tasks.length) return finallCallback(...args)
//                 this.tasks[index++](...args,next)
//                }
//                next()
//             }
//         }
//         let h=new AsyncSeriesHook(['name'])
//         h.tapAsync('node',(name,cb)=>{
//             setTimeout(function() {
//             console.log('node',name)
//             cb()
//             }, 1000);
//         })
//         h.tapAsync('js',(name,cb)=>{
//                 setTimeout(function() {
//                     console.log('js',name)
//                     cb()
//                     }, 1000);
//         })
//         h.callAsync('wjy',()=>{
//             console.log('end')
//         })
// promise版的串行
// class AsyncSeries{
//             constructor(task){
//                 this.tasks=[]
//             }
//             tappromise(name,fun){
//                 this.tasks.push(fun)
//             }
//             promise(...args){
//               let [first,...other]=this.tasks
//               return other.reduce((p,n)=>{
//                return p.then(()=>n(...args))
//               },first(...args))
//             }
//         }
//         let h=new AsyncSeries(['name'])
//         h.tappromise('node',(name)=>{
//             return new Promise((resolve,reject)=>{
//             setTimeout(function() {
//             console.log('node',name)
//             resolve()
//             }, 1000);
//             })
//         })
//         h.tappromise('js',(name)=>{
//             return new Promise((resolve,reject)=>{
//                 setTimeout(function() {
//                     console.log('js',name)
//                     resolve()
//                     }, 1000);
//                 })
//         })
//         h.promise('wjy').then(()=>{
//             console.log('end')
//         })

// let {AsyncSeriesWaterfallHook} = require('tapable')
// class Lesson{
//     constructor(){
//         this.hooks={
//             arch:new AsyncSeriesWaterfallHook(['name'])
//         }
//     }
//     tap(){
//         this.hooks.arch.tapAsync('node',(name,cb)=>{
//             setTimeout(function() {
//                 console.log('node',name)
//                 cb(null,'result')
//             }, 1000);
//         })
//         this.hooks.arch.tapAsync('js',(data,cb)=>{
//             setTimeout(function() {
//                 console.log('js',data) // 上一次调用的结果传到下一次
//                 cb('error','result')
//             }, 1000);
//         })
//     }
//     start(){
//         this.hooks.arch.callAsync('wjy',()=>{
//             console.log('haha') //最后执行
//         })
//     }
// }
// let l = new Lesson()
// l.tap()
// l.start()

// 自己实现
// class AsyncSeriesWaterfallHook{
//             constructor(task){
//                 this.tasks=[]
//             }
//             tapAsync(name,fun){
//                 this.tasks.push(fun)
//             }
//             callAsync(...args){
//                 let finallCallback=args.pop()
//                 let index=0
//                 let next=(err,result)=>{
//                    let task=this.tasks[index]
//                    if(!task) return finallCallback()
//                    if(index===0){
//                     task(...args,next)
//                    }else{
//                     task(result,next)                    
//                    }
//                    index++
//                 }
//                 next()
//             }
//         }
//         let h=new AsyncSeriesWaterfallHook(['name'])
//         h.tapAsync('node',(name,cb)=>{
//             setTimeout(function() {
//             console.log('node',name)
//             cb(null,'noderesult')
//             }, 1000);
//         })
//         h.tapAsync('js',(data,cb)=>{
//                 setTimeout(function() {
//                     console.log('js',data)
//                     cb(null,'jsresult')
//                     }, 1000);
//         })
//         h.callAsync('wjy',()=>{
//             console.log('end')
//         })